home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / text / hyper / ADtoHT2_0.lha / File.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-19  |  19.7 KB  |  798 lines

  1. /************************************************************************/
  2. /*                                                                      */
  3. /* The file functions.                                                  */
  4. /* These functions handle one read-file and one write-file.             */
  5. /*                                                                      */
  6. /************************************************************************/
  7.  
  8. #include <proto/exec.h>
  9. #include <proto/dos.h>
  10.  
  11. /* SAS/C V5.10b is broken, so we can't include clib/alib_protos.h */
  12. void NewList(struct List *);
  13.  
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <ctype.h>
  18. #include <stdarg.h>
  19. #include <errno.h>
  20.  
  21. /************************************************************************/
  22.  
  23. #include "main.h"
  24. #include "File.h"
  25.  
  26. /************************************************************************/
  27.  
  28. char *ReadFilename, *WriteFilename;
  29.  
  30. static FILE *WriteHandle, *ReadHandle;
  31. static ULONG ReadLineNo;
  32. static int ReadColumn;
  33.  
  34. static struct MinList UnreadList;
  35.  
  36. /************************************************************************/
  37. /*                                                                      */
  38. /* Return complete filename                                             */
  39. /*                                                                      */
  40. /************************************************************************/
  41.  
  42. static char *
  43. GetFilename (int DirNumber, char *Name)
  44.  
  45. {
  46.   int FilenameLength;
  47.   char *Filename;
  48.   int FirstError;
  49.  
  50.   FirstError=TRUE;
  51.   FilenameLength = 256;
  52.   while (TRUE)
  53.     {
  54.       Filename = xmalloc (FilenameLength);
  55.     NoMemReTry:
  56.       if (NameFromLock (Dirs[CURRENTDIR], Filename, FilenameLength))
  57.     {
  58.       if (DirNumber == CURRENTDIR || AddPart (Filename, Arguments.Dirs[DirNumber], FilenameLength))
  59.         {
  60.           if (AddPart (Filename, Name, FilenameLength))
  61.         {
  62.           return Filename;
  63.         }
  64.         }
  65.     }
  66.       else
  67.     {
  68.       switch(IoErr())
  69.         {
  70.         case ERROR_NO_FREE_STORE:
  71.           {
  72.         if (FirstError)
  73.           {
  74.             errno=ENOMEM;
  75.             perror("Current directory");
  76.             FirstError=FALSE;
  77.           }
  78.         Delay(2*TICKS_PER_SECOND);
  79.         if (!CheckSignal(SIGBREAKF_CTRL_C))
  80.           {
  81.             goto NoMemReTry;
  82.           }
  83.         errno=ERROR_BREAK;
  84.         perror(NULL);
  85.         CloseAll(RETURN_ERROR);
  86.           }
  87.           break;
  88.  
  89.         case ERROR_LINE_TOO_LONG:
  90.           {
  91.         free (Filename);
  92.         FilenameLength += 256;
  93.           }
  94.           break;
  95.  
  96.         default:
  97.           {
  98.         errno=IoErr();
  99.         perror ("Current directory");
  100.         CloseAll (RETURN_ERROR);
  101.           }
  102.           break;
  103.  
  104.         }
  105.     }
  106.     }
  107.   /* not reached */
  108. }
  109.  
  110. /************************************************************************/
  111. /*                                                                      */
  112. /* Open a file for reading.                                             */
  113. /*                                                                      */
  114. /************************************************************************/
  115.  
  116. void
  117. ROpen (int DirNumber, char *Name)
  118.  
  119. {
  120.   int FirstError;
  121.  
  122.   ReadFilename = GetFilename (DirNumber, Name);
  123.  
  124.   NewList ((struct List *) &UnreadList);
  125.  
  126.   CurrentDir (Dirs[DirNumber]);
  127.   FirstError=TRUE;
  128.   while (!(ReadHandle = fopen (ReadFilename, "r")))
  129.     {
  130.       if (errno==ENOMEM)
  131.     {
  132.       if (FirstError)
  133.         {
  134.           perror(ReadFilename);
  135.           FirstError=FALSE;
  136.         }
  137.       Delay(2*TICKS_PER_SECOND);
  138.       if (CheckSignal(SIGBREAKF_CTRL_C))
  139.         {
  140.           errno=ERROR_BREAK;
  141.           perror(NULL);
  142.           CloseAll(RETURN_ERROR);
  143.         }
  144.     }
  145.       else
  146.     {
  147.       perror (ReadFilename);
  148.       CloseAll (RETURN_ERROR);
  149.     }
  150.     }
  151.   SetVBuf (fileno(ReadHandle), NULL, BUF_FULL, 16 * 1024);
  152.  
  153.   ReadLineNo = 1;
  154.   ReadColumn = 0;
  155. }
  156.  
  157. /************************************************************************/
  158. /*                                                                      */
  159. /* Create a directory tree                                              */
  160. /*                                                                      */
  161. /************************************************************************/
  162.  
  163. static void
  164. CreateDirectory (char *Name)
  165.  
  166. {
  167.   BPTR DirLock;
  168.  
  169.   if (!Name[0])
  170.     {
  171.       return;
  172.     }
  173.  
  174.   if ((DirLock = Lock (Name, SHARED_LOCK)))
  175.     {
  176.       UnLock (DirLock);
  177.       return;
  178.     }
  179.  
  180.   if (IoErr () == ERROR_OBJECT_NOT_FOUND)
  181.     {
  182.       char *t;
  183.  
  184.       t = PathPart (Name);
  185.       if (t != Name)
  186.     {
  187.       char c;
  188.  
  189.       c = *t;
  190.       *t = '\0';
  191.       CreateDirectory (Name);
  192.       *t = c;
  193.     }
  194.       if ((DirLock = CreateDir (Name)))
  195.     {
  196.       UnLock (DirLock);
  197.       return;
  198.     }
  199.     }
  200.   errno=IoErr();
  201.   perror (Name);
  202.   CloseAll (RETURN_ERROR);
  203. }
  204.  
  205. /************************************************************************/
  206. /*                                                                      */
  207. /* Open a file for writing.                                             */
  208. /*                                                                      */
  209. /************************************************************************/
  210.  
  211. void
  212. WOpen (int DirNumber, char *Name)
  213.  
  214. {
  215.   WriteFilename = GetFilename (DirNumber, Name);
  216.  
  217.   if (Pass2)
  218.     {
  219.       char *t;
  220.       char c;
  221.       int FirstError;
  222.  
  223.       CurrentDir (Dirs[DirNumber]);
  224.       t = PathPart (WriteFilename);
  225.       c = *t;
  226.       *t = '\0';
  227.       CreateDirectory (WriteFilename);
  228.       *t = c;
  229.       FirstError=TRUE;
  230.       while (!(WriteHandle = fopen (WriteFilename, "w")))
  231.     {
  232.       if (errno==ENOMEM)
  233.         {
  234.           if (FirstError)
  235.         {
  236.           perror(WriteFilename);
  237.           FirstError=FALSE;
  238.         }
  239.           Delay(2*TICKS_PER_SECOND);
  240.           if (CheckSignal(SIGBREAKF_CTRL_C))
  241.         {
  242.           errno=ERROR_BREAK;
  243.           perror(NULL);
  244.           SetRC(RETURN_ERROR);
  245.           break;
  246.         }
  247.         }
  248.       else
  249.         {
  250.           perror (WriteFilename);
  251.           SetRC (RETURN_ERROR);
  252.           break;
  253.         }
  254.     }
  255.       if (WriteHandle)
  256.     {
  257.       SetVBuf (fileno(WriteHandle), NULL, BUF_FULL, 16 * 1024);
  258.     }
  259.     }
  260. }
  261.  
  262. /************************************************************************/
  263. /*                                                                      */
  264. /* Close the read-file.                                                 */
  265. /*                                                                      */
  266. /************************************************************************/
  267.  
  268. void
  269. RClose (void)
  270.  
  271. {
  272.   if (ReadHandle)
  273.     {
  274.       fclose (ReadHandle);
  275.       ReadHandle = NULL;
  276.       free (ReadFilename);
  277.     }
  278.  
  279.   if (UnreadList.mlh_Head)
  280.     {
  281.       struct Word *Word;
  282.  
  283.       while ((Word = (struct Word *) RemTail ((struct List *) &UnreadList)))
  284.     {
  285.       FreeWord (Word);
  286.     }
  287.     }
  288. }
  289.  
  290. /************************************************************************/
  291. /*                                                                      */
  292. /* Close the write-file.                                                */
  293. /*                                                                      */
  294. /************************************************************************/
  295.  
  296. void
  297. WClose (void)
  298.  
  299. {
  300.   if (WriteHandle)
  301.     {
  302.       if (fclose (WriteHandle)==EOF)
  303.     {
  304.       perror (WriteFilename);
  305.       SetRC (RETURN_ERROR);
  306.     }
  307.       SetProtection (WriteFilename, FIBF_EXECUTE);
  308.       WriteHandle = NULL;
  309.     }
  310.   if (WriteFilename)
  311.     {
  312.       free(WriteFilename);
  313.       WriteFilename=NULL;
  314.     }
  315. }
  316.  
  317. /************************************************************************/
  318. /*                                                                      */
  319. /* Read a word from the read-file. This is just an internal function.    */
  320. /*                                                                      */
  321. /************************************************************************/
  322.  
  323. struct Word *BasicReadWord (int AllowEOF)
  324.  
  325. {
  326.   struct Word *NewWord;
  327.  
  328.   if (CheckSignal (SIGBREAKF_CTRL_C))
  329.     {
  330.       errno=ERROR_BREAK;
  331.       perror (NULL);
  332.       CloseAll (RETURN_WARN);
  333.     }
  334.  
  335.   if (!(NewWord = (struct Word *) RemTail ((struct List *) &UnreadList)))
  336.     {
  337.       struct Word Word;
  338.       int StartColumn;
  339.  
  340.       memset (&Word, 0, sizeof (Word));
  341.  
  342.       StartColumn = ReadColumn;
  343.  
  344.       NewWord = NULL;
  345.       while (!NewWord)
  346.     {
  347.       static char *InputBuffer;
  348.       static size_t InputBufferSize;
  349.  
  350.       int c;
  351.  
  352.       Word.Line = ReadLineNo;
  353.  
  354.       c = fgetc (ReadHandle);
  355.       ReadColumn++;
  356.       if (c == '\t')
  357.         {
  358.           /* really +8, but we have already added 1 */
  359.           ReadColumn = (ReadColumn + 7) & ~7;
  360.         }
  361.       else if (isalpha (c) || c == '_')
  362.         {
  363.           Word.Whitespace = ReadColumn - StartColumn - 1;
  364.           while (isalpha (c) || isdigit (c) || c == '_')
  365.         {
  366.           if ((isupper (c) && Word.Length > 0) ||
  367.               isdigit (c) ||
  368.               c == '_')
  369.             {
  370.               Word.Special = TRUE;
  371.             }
  372.           if (Word.Length+1>=InputBufferSize)
  373.             {
  374.               InputBuffer=xrealloc(InputBuffer,InputBufferSize+=128);
  375.             }
  376.           InputBuffer[Word.Length++] = c;
  377.           c = fgetc (ReadHandle);
  378.           ReadColumn++;
  379.         }
  380.           if (ferror (ReadHandle))
  381.         {
  382.           perror (ReadFilename);
  383.           CloseAll (RETURN_ERROR);
  384.         }
  385.           ungetc (c,ReadHandle);
  386.           ReadColumn--;
  387.  
  388.           InputBuffer[Word.Length] = '\0';
  389.           NewWord = xmalloc (sizeof (*NewWord) + Word.Length);
  390.           *NewWord = Word;
  391.           strcpy (NewWord->Word, InputBuffer);
  392.         }
  393.       else if (isdigit(c))
  394.         {
  395.           Word.Whitespace = ReadColumn - StartColumn - 1;
  396.           while (isdigit(c) || c=='x')
  397.         {
  398.           if (Word.Length+1>=InputBufferSize)
  399.             {
  400.               InputBuffer=xrealloc(InputBuffer,InputBufferSize+=128);
  401.             }
  402.           InputBuffer[Word.Length++]=c;
  403.           c=fgetc(ReadHandle);
  404.           ReadColumn++;
  405.         }
  406.           if (ferror(ReadHandle))
  407.         {
  408.           perror(ReadFilename);
  409.           CloseAll(RETURN_ERROR);
  410.         }
  411.           ungetc(c,ReadHandle);
  412.           ReadColumn--;
  413.  
  414.           InputBuffer[Word.Length] = '\0';
  415.           NewWord = xmalloc (sizeof (*NewWord) + Word.Length);
  416.           *NewWord = Word;
  417.           strcpy (NewWord->Word, InputBuffer);
  418.         }
  419.       else if (c == '\n')
  420.         {
  421.           Word.Newline++;
  422.           StartColumn = 0;
  423.           ReadColumn = 0;
  424.           ReadLineNo++;
  425.         }
  426.       else if (c == EOF)
  427.         {
  428.           if (ferror(ReadHandle))
  429.         {
  430.           perror (ReadFilename);
  431.           CloseAll (RETURN_ERROR);
  432.         }
  433.           if (!AllowEOF)
  434.         {
  435.           fprintf (stderr, "%s: unexpected end of file\n", ReadFilename);
  436.           CloseAll (RETURN_ERROR);
  437.         }
  438.           NewWord = xmalloc (sizeof (*NewWord));
  439.           *NewWord = Word;
  440.           NewWord->Word[0] = '\0';
  441.           NewWord->Whitespace = 0;
  442.           NewWord->Newline = (NewWord->Newline > 0);
  443.           NewWord->Special=TRUE;
  444.         }
  445.       else if (c != ' ')
  446.         {
  447.           if (c == 0x0c)
  448.         {
  449.           ReadColumn = 0;
  450.           Word.Whitespace = 0;
  451.         }
  452.           else
  453.         {
  454.           Word.Whitespace = ReadColumn - StartColumn - 1;
  455.         }
  456.           NewWord = xmalloc (sizeof (*NewWord) + 1);
  457.           *NewWord = Word;
  458.           NewWord->Word[0] = c;
  459.           NewWord->Word[1] = '\0';
  460.           NewWord->Length = 1;
  461.           NewWord->Special = TRUE;
  462.         }
  463.     }
  464.     }
  465.   return NewWord;
  466. }
  467.  
  468.  
  469. /************************************************************************/
  470. /*                                                                      */
  471. /* Concat several words to one.                        */
  472. /* Intervening whitespace and newlines are ignored.            */
  473. /* The individual words are freed.                    */
  474. /*                                                                      */
  475. /************************************************************************/
  476.  
  477. static struct Word *ConcatWords(struct Word *FirstWord, ...)
  478.  
  479. {
  480.   struct Word **CurrentWord;
  481.   struct Word *NewWord;
  482.   size_t NewLength;
  483.   char *t;
  484.  
  485.   NewLength=0;
  486.   for (CurrentWord=&FirstWord; *CurrentWord; CurrentWord++)
  487.     {
  488.       NewLength+=(*CurrentWord)->Length;
  489.     }
  490.  
  491.   NewWord=xmalloc(sizeof(*NewWord)+NewLength);
  492.   NewWord->Line=FirstWord->Line;
  493.   NewWord->Whitespace=FirstWord->Whitespace;
  494.   NewWord->Newline=FirstWord->Newline;
  495.   NewWord->Special=TRUE;
  496.   NewWord->Length=NewLength;
  497.  
  498.   t=NewWord->Word;
  499.   for (CurrentWord=&FirstWord; *CurrentWord; CurrentWord++)
  500.     {
  501.       t=stpcpy(t,(*CurrentWord)->Word);
  502.       FreeWord(*CurrentWord);
  503.     }
  504.  
  505.   return NewWord;
  506. }
  507.  
  508. /************************************************************************/
  509. /*                                                                      */
  510. /* Read a word. This is the real function that will handle all known    */
  511. /* exceptions to the normal word definition.                */
  512. /*                                                                      */
  513. /************************************************************************/
  514.  
  515. struct Word *ReadWord(int AllowEOF)
  516.  
  517. {
  518.   struct Word *Word;
  519.   struct Word *NextWord;
  520.  
  521.   Word=BasicReadWord(AllowEOF);
  522.   NextWord=BasicReadWord(TRUE);
  523.  
  524.   /* 8svx */
  525.   if (!strcmp(Word->Word,"8"))
  526.     {
  527.       if (!NextWord->Whitespace && !NextWord->Newline && !strcasecmp(NextWord->Word,"svx"))
  528.     {
  529.       Word=ConcatWords(Word,NextWord,NULL);
  530.       NextWord=BasicReadWord(TRUE);
  531.     }
  532.     }
  533.  
  534.   /* -handler */
  535.   if (!NextWord->Whitespace && !NextWord->Newline && !strcmp(NextWord->Word,"-"))
  536.     {
  537.       struct Word *NextNextWord;
  538.  
  539.       NextNextWord=BasicReadWord(TRUE);
  540.       if (!NextNextWord->Whitespace && !NextNextWord->Newline && !strcasecmp(NextNextWord->Word,"handler"))
  541.     {
  542.       Word=ConcatWords(Word,NextWord,NextNextWord,NULL);
  543.       NextWord=BasicReadWord(TRUE);
  544.     }
  545.       else
  546.     {
  547.       UnreadWord(NextNextWord);
  548.     }
  549.     }
  550.  
  551.   /* .irgendwas */
  552.   if (!NextWord->Whitespace && !NextWord->Newline && !strcmp(NextWord->Word,"."))
  553.     {
  554.       struct Word *NextNextWord;
  555.  
  556.       NextNextWord=BasicReadWord(TRUE);
  557.       if (!NextNextWord->Whitespace && !NextNextWord->Newline && !NextNextWord->Special)
  558.     {
  559.       Word=ConcatWords(Word,NextWord,NextNextWord,NULL);
  560.       NextWord=BasicReadWord(TRUE);
  561.     }
  562.       else
  563.     {
  564.       UnreadWord(NextNextWord);
  565.     }
  566.     }
  567.   UnreadWord(NextWord);
  568.   return Word;
  569. }
  570.  
  571. /************************************************************************/
  572. /*                                                                      */
  573. /* Unread a word back to the read-file                                  */
  574. /*                                                                      */
  575. /************************************************************************/
  576.  
  577. void UnreadWord (struct Word *Word)
  578.  
  579. {
  580.   AddTail ((struct List *) &UnreadList, (struct Node *) &Word->Node);
  581. }
  582.  
  583. #ifndef FreeWord
  584. /************************************************************************/
  585. /*                                                                      */
  586. /* Free a read word                                                     */
  587. /*                                                                      */
  588. /************************************************************************/
  589.  
  590. void FreeWord (struct Word *Word)
  591.  
  592. {
  593.   free (Word);
  594. }
  595. #endif
  596.  
  597. /************************************************************************/
  598. /*                                                                      */
  599. /* Read until a terminating word                                        */
  600. /* The terminator is unread                                             */
  601. /*                                                                      */
  602. /************************************************************************/
  603.  
  604. char *
  605. ReadUntil (char *Terminator)
  606.  
  607. {
  608.   struct MinList WordList;
  609.   struct Word *Word;
  610.   size_t Length;
  611.   char *Text, *t;
  612.  
  613.   NewList ((struct List *) &WordList);
  614.   Length = 1;
  615.   Word = ReadWord (FALSE);
  616.   while (strcmp (Word->Word, Terminator))
  617.     {
  618.       AddTail ((struct List *) &WordList, (struct Node *) Word);
  619.       Length += Word->Length + Word->Whitespace;
  620.       Word = ReadWord (FALSE);
  621.     }
  622.   UnreadWord (Word);
  623.   t = Text = xmalloc (Length);
  624.   while ((Word = (struct Word *) RemHead ((struct List *) &WordList)))
  625.     {
  626.       while (Word->Whitespace)
  627.     {
  628.       *(t++) = ' ';
  629.       Word->Whitespace--;
  630.     }
  631.       t = stpcpy (t, Word->Word);
  632.       FreeWord (Word);
  633.     }
  634.   return Text;
  635. }
  636.  
  637. /************************************************************************/
  638. /*                                                                      */
  639. /* Write a formatted string to the write-file                           */
  640. /*                                                                      */
  641. /************************************************************************/
  642.  
  643. void
  644. WPrintf (char *FormatString,...)
  645.  
  646. {
  647.   if (WriteHandle)
  648.     {
  649.       va_list ParamList;
  650.  
  651.       va_start(ParamList,FormatString);
  652.       if (vfprintf (WriteHandle, FormatString, ParamList) == EOF)
  653.     {
  654.       va_end(ParamList);
  655.       perror (WriteFilename);
  656.       CloseAll (RETURN_ERROR);
  657.     }
  658.       va_end(ParamList);
  659.     }
  660. }
  661.  
  662. /************************************************************************/
  663. /*                                                                      */
  664. /* Write the header for an AmigaGuide file                              */
  665. /*                                                                      */
  666. /************************************************************************/
  667.  
  668. void
  669. WriteHeader (char *Database, char *Master)
  670.  
  671. {
  672.   if (Pass2)
  673.     {
  674.       struct DateTime DateTime;
  675.       char StrDate[LEN_DATSTRING], StrTime[LEN_DATSTRING];
  676.  
  677.       DateStamp (&DateTime.dat_Stamp);
  678.       DateTime.dat_Format = FORMAT_DOS;
  679.       DateTime.dat_Flags = 0;
  680.       DateTime.dat_StrDay = NULL;
  681.       DateTime.dat_StrDate = StrDate;
  682.       DateTime.dat_StrTime = StrTime;
  683.  
  684.       DateToStr (&DateTime);
  685.  
  686.       WPrintf ("@DATABASE \x22%s\x22\n", Database);
  687.       if (Master)
  688.     WPrintf ("@MASTER   \x22%s\x22\n", Master);
  689.       WPrintf ("@REMARK   This file was created by " PROGRAM_NAME " " PROGRAM_VERSION " on %s %s\n"
  690.            "@REMARK   Do not edit\n"
  691.            "@REMARK   ADtoHT is " PROGRAM_COPYRIGHT "\n",
  692.            StrDate, StrTime);
  693.     }
  694. }
  695.  
  696. /************************************************************************/
  697. /*                                                                      */
  698. /* Write a words white-space to the write-file                          */
  699. /*                                                                      */
  700. /************************************************************************/
  701.  
  702. void
  703. WriteWhitespace (struct Word *Word)
  704.  
  705. {
  706.   while (Word->Newline)
  707.     {
  708.       WPrintf ("\n");
  709.       Word->Newline--;
  710.     }
  711.   while (Word->Whitespace)
  712.     {
  713.       WPrintf (" ");
  714.       Word->Whitespace--;
  715.     }
  716. }
  717.  
  718. /************************************************************************/
  719. /*                                                                      */
  720. /* Write a word to the write-file                                       */
  721. /*                                                                      */
  722. /************************************************************************/
  723.  
  724. void
  725. WriteWord (struct Word *Word)
  726.  
  727. {
  728.   WriteWhitespace (Word);
  729.   if (Word->Length == 1)
  730.     {
  731.       switch (Word->Word[0])
  732.     {
  733.     case '\\':
  734.       WPrintf ("\\\\");
  735.       return;
  736.     case '@':
  737.       WPrintf ("@@");
  738.       return;
  739.     }
  740.     }
  741.   WPrintf ("%s", Word->Word);
  742. }
  743.  
  744. /************************************************************************/
  745. /*                                                                      */
  746. /* Skip Read-File until 0x0c is found                                    */
  747. /* Returns the last char read (may be -1 == EOF)                        */
  748. /*                                                                      */
  749. /************************************************************************/
  750.  
  751. long
  752. ReadSkip (void)
  753.  
  754. {
  755.   long c;
  756.   struct Word *Word;
  757.  
  758.   while ((Word=(struct Word *)RemTail((struct List *)&UnreadList)))
  759.     {
  760.       if (Word->Word[0]==0x0c)
  761.     {
  762.       return (long)Word->Word[0];
  763.     }
  764.       if (!Word->Word[0])
  765.     {
  766.       return -1;
  767.     }
  768.       FreeWord(Word);
  769.     }
  770.  
  771.   do
  772.     {
  773.       c = fgetc (ReadHandle);
  774.     }
  775.   while (c != 0x0c && c != EOF);
  776.  
  777.   return c;
  778. }
  779.  
  780. /************************************************************************/
  781. /*                                                                      */
  782. /* Output a bold, centered headline                                     */
  783. /*                                                                      */
  784. /************************************************************************/
  785.  
  786. void 
  787. WHeadline (char *Text)
  788.  
  789. {
  790.   int i;
  791.  
  792.   for (i = (*Arguments.Width - strlen (Text) - (*Arguments.Version >= 39)) / 2; i; i--)
  793.     {
  794.       WPrintf (" ");
  795.     }
  796.   WPrintf (*Arguments.Version >= 39 ? "@{b}%s@{ub}\n" : "%s\n", Text);
  797. }
  798.